package com.tjc.common.pool;


import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @Author: tjc
 * @description
 * @Date Created in 22:01 2022-08-04
 */
public class GenericObjectPool<T> extends BaseObjectPool<T> {

    LinkedBlockingDeque<PooledObject<T>> idleObjects;
    private final PooledObjectFactory<T> factory;

    private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_VALUE;
    private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_VALUE;
    private volatile int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_VALUE;

    private volatile Duration maxWaitDuration = GenericObjectPoolConfig.DEFAULT_MAX_WAIT;
    private volatile boolean getBlockWhenExhausted = GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;

    public GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig<T> config) {
        if (factory == null) {
            throw new IllegalArgumentException("factory may not be null");
        }
        this.factory = factory;
        idleObjects = new LinkedBlockingDeque<>();
        setConfig(config);
    }

    private void setConfig(GenericObjectPoolConfig<T> config) {
        setMaxIdle(config);
        setMaxTotal(config);
        setMinIdle(config);
    }

    private void setMaxTotal(GenericObjectPoolConfig<T> config) {
        this.maxTotal = config.getMaxTotal();
    }

    private void setMinIdle(GenericObjectPoolConfig<T> config) {
        this.minIdle = config.getMinIdle();
    }

    private void setMaxIdle(GenericObjectPoolConfig<T> config) {
        this.maxIdle = config.getMaxIdle();
    }

    private final Duration getMaxWaitDuration() {
        return maxWaitDuration;
    }

    @Override
    public T borrowObject() throws Exception {
        return borrowObject(getMaxWaitDuration());
    }

    private T borrowObject(Duration maxWaitDuration) {
        assertOpen();
        // todo
        PooledObject<T> p = null;

        final boolean blockWhenExhausted = getBlockWhenExhausted();
        boolean create;

        while (p == null) {
            p = idleObjects.pollFirst();
            if (p == null) {
                p = create();
                if (p != null) {
                    create = true;
                }
            }

            if (blockWhenExhausted) {
                if (p == null) {

                }
            }

        }
        return null;
    }

    private PooledObject<T> create() {
        return null;
    }

    private boolean getBlockWhenExhausted() {
        return getBlockWhenExhausted;
    }

    private void assertOpen() {
        if (isClosed()) {
            throw new IllegalStateException("Pool not open");
        }
    }

    private boolean isClosed() {
        return closed;
    }

    @Override
    public void returnObject(T obj) throws Exception {

    }

    @Override
    public void invalidateObject(T obj) throws Exception {

    }

    private class IdentityWrapper<T> {
        private T instance;

        public IdentityWrapper(T instance) {
            this.instance = instance;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            IdentityWrapper<?> that = (IdentityWrapper<?>) o;
            return Objects.equals(instance, that.instance);
        }

        @Override
        public int hashCode() {
            return Objects.hash(instance);
        }
    }
}
